-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Proposing ZendMM Observer API #11758
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps the ZEND_API
parts of this file should be moved to Zend/observer.h
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, there is already a Zend/zend_observer.h
file, but this is for the Zend Engine. I think this could lead to misunderstandings. Personally I am totally okay with having this in Zend/zend_alloc.h
as everything regarding the ZendMM is there. We might consider moving it to a Zend/zend_alloc_observer.h
file to keep the naming clear.
Personally I would leave it as is, but I do not have any hard feelings the one way or the other.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this!
Is there a particular reason for requiring that observers are registered during startup/MINIT? Assuming a memory profiling extension, registering observers during MINIT adds unnecessary overhead when not profiling.
@arnaud-lb The overhead would be only once per ginit, with a relatively low overhead. I think that's pretty reasonable. The alternative would be that memory profiling extensions have to register in each rinit, and PHP would have to free these in rshutdowns (or at least check for it, even if nothing happens). Not sure whether doing that would really have less overhead. |
I was referring to overhead in the allocation functions, since they take the "custom heap" path when some observers are enabled. But I was missing that extensions would disable the observers when they are not needed. As long as they do, this will have no overhead, so that's fine. |
Probably because
We can have a race condition between steps 2 and 4, losing the value from the thread that finished first. Furthermore, we'd need to move this to a shared global for NTS. If we could register observers dynamically we would likely also need to offer API to unregister them. As you mentioned, an extension that registers an observer could disable it by default unless profiling was requested. Edit: Oh, they are appended. But the issue remains. |
I got that we can not mutate
Couldn't we obtain the same functionality if |
@arnaud-lb Of course, in my comment I missed that observers can be enabled/disabled per request and so can't be shared across processes/threads. Your suggestion to enable per request sounds simpler. The overhead of the allocation per request is negligible, and only relevant when memory profiling. Memory profiling leaking across requests doesn't seem particularly useful. |
Hey @arnaud-lb and @iluuu1994,
I'll play with this and check the usage, but I think it makes sense this way especially when the malloc() and the free() are negligible. What do you think? |
One thing in favour of having a unregister function is that this would allow an extension to expose observing memory allocations to userspace (add a |
a893bbf
to
c0d92b2
Compare
No worries, and I hope you are feeling better now!
Thank you for these changes. This is simpler and it's probably easier to use the API in the right way as well. Agreed that we should unregister observers in mm_shutdown (including when full=false), as this would also prevent accidentally leaking observers to next requests. I will try the API on memprof later this week (probably on Friday) to check that it's suitable for more than one extension. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks much simpler, thank you @realFlowControl!
I do think we should have some simple tests in |
0dcb137
to
59845a9
Compare
0f367e0
to
02bca4d
Compare
02bca4d
to
8fa36be
Compare
Hello everyone,
this PR proposes a ZendMM Observer API which allows for observing memory allocations in the Zend Memory Manager. The only current way to observer the ZendMM is via the
zend_mm_set_custom_handlers()
function which is meant to bring your own memory manager. Using this API has some side effects which you need to work around:Additionally you need to be aware of neighbouring extensions and handle everything in order.
This proposal flips this by keeping track of observers and not interfering with ZendMM internals. It will only be an observer that calls observing functions on
malloc
,free
andrealloc
and ZendMM garbage collection (gc_mem_caches()
user land call or ZendMM internal cleanup when allocating but no free slots available).It has no overhead as long as no observer is installed or when all observers that are installed are disabled.
An example of how to use the API can be found at https://github.com/realFlowControl/zendmmobserver/blob/main/zendmmobserver.c
Big picture:
zend_mm_observers_register()
zend_mm_observer_disable()
/zend_mm_observer_enable()
to disable / enable a registered observerUPDATE
We made it less complex and it looks like this:
zend_mm_observers_register()
can be called in and after RINITzend_mm_observers_unregister()
in or before RSHUTDOWNzend_mm_shutdown()
for you after every request